package com.maistars.spider.controller;

import com.alibaba.fastjson.JSONObject;
import com.maistars.spider.common.constants.PageType;
import com.maistars.spider.common.constants.StoreType;
import com.maistars.spider.common.util.HttpInvokerUtil;
import com.maistars.spider.repository.dao.CrawlerTaskDao;
import com.maistars.spider.repository.model.CrawlerFieldRulePO;
import com.maistars.spider.repository.model.CrawlerPageRulePO;
import com.maistars.spider.repository.model.CrawlerSiteRulePO;
import com.maistars.spider.repository.model.CrawlerTaskPO;
import com.maistars.spider.service.domain.capture.CapturedPage;
import com.maistars.spider.service.domain.render.RenderConfig;
import com.maistars.spider.service.domain.rule.FieldRule;
import com.maistars.spider.service.domain.rule.PageRule;
import com.maistars.spider.service.domain.rule.SiteRule;
import com.maistars.spider.service.domain.store.TaskStoreConfig;
import com.maistars.spider.service.domain.task.CrawlerTask;
import com.maistars.spider.service.domain.task.CrawlerTaskInst;
import com.maistars.spider.service.render.RenderService;
import com.maistars.spider.view.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @author dhr
 * @date 2022/5/14 16:58
 */
@Controller
@RequestMapping("/taskInst")
@Slf4j
public class TaskInstController {

    private static String CHROME_DRIVER_PATH = "/Users/dhr/chromedriver/chromedriver";

    @Autowired
    private CrawlerTaskDao crawlerTaskDao;

    /**
     * 测试采集
     *
     * @param request
     * @return
     */
    @RequestMapping("/testCollect")
    @ResponseBody
    public ResponseResult<Map<String, Object>> testCollect(HttpServletRequest request) {
        ResponseResult<Map<String, Object>> responseResult = new ResponseResult<>();
        responseResult.setCode(100);

        String taskId = request.getParameter("taskId");
        try {
            // 查询任务模板
            CrawlerTaskPO crawlerTaskPO = crawlerTaskDao.getCrawlerTask(Integer.parseInt(taskId));
            // 查询站点规则(种子规则)
            List<CrawlerSiteRulePO> crawlerSiteRulePOS = crawlerTaskDao.listCrawlerSiteRules(crawlerTaskPO.getId());
            // 查询页面规则
            List<CrawlerPageRulePO> crawlerPageRulePOS = crawlerTaskDao.listCrawlerPageRules(crawlerTaskPO.getId());
            // 定义渲染
            RenderService renderService = new RenderService();

            CrawlerTask crawlerTask = CrawlerTask.builder()
                    .taskId(Integer.parseInt(taskId))
                    .taskName(crawlerTaskPO.getTaskName())
                    .comment(crawlerTaskPO.getComment())
                    .priority(crawlerTaskPO.getPriority())
                    .build();

            // 创建任务配置
            TaskStoreConfig taskStoreConfig = TaskStoreConfig.builder()
                    .capturedPageStoreType(StoreType.CONSOLE.getValue())
                    .extractedFieldsStoreType(StoreType.CONSOLE.getValue())
                    .build();

            // 定义爬虫实例
            CrawlerTaskInst crawlerTaskInst = CrawlerTaskInst.builder()
                    .taskInstId(2999)
                    .crawlerTask(crawlerTask)
                    .startTime(new Date())
                    .status(1)
                    .capturedPageThreadNum(8)
                    .taskStoreConfig(taskStoreConfig)
                    .capturedPageSuccessCount(new HashMap<>())
                    .capturedPageTotoalCount(new HashMap<>())
                    .maxCaptureUrlNums(new HashMap<>())
                    .build();

            // 定时站点规则
            SiteRule siteRule = SiteRule.builder()
                    .id(crawlerSiteRulePOS.get(0).getId())
                    .siteRule(crawlerSiteRulePOS.get(0).getSiteRule())
                    .ruleName(crawlerSiteRulePOS.get(0).getRuleName())
                    .task(crawlerTask)
                    .cronConfig(crawlerSiteRulePOS.get(0).getCronConfig())
                    .executionEndTime(crawlerSiteRulePOS.get(0).getExecutionEndTime())
                    .executionStartTime(crawlerSiteRulePOS.get(0).getExecutionStartTime())
                    .build();

            if (crawlerPageRulePOS == null || crawlerPageRulePOS.isEmpty()) {
                responseResult.setCode(400);
                responseResult.setMsg("触发采集出错");
                return responseResult;
            }

            List<PageRule> pageRules = new ArrayList<>();

            for (int i = 0; i < crawlerPageRulePOS.size(); i++) {
                CrawlerPageRulePO crawlerPageRulePO = crawlerPageRulePOS.get(i);

                JSONObject renderConfigObj = JSONObject.parseObject(crawlerPageRulePO.getRenderConfig() == null ? "{}" : crawlerPageRulePO.getRenderConfig());
                RenderConfig renderConfig = new RenderConfig();
                renderConfig.setHtmlHandler(renderService.getDefaultHtmlHandler());
                renderConfig.setMethod(renderConfigObj.getString("method") == "post" ? HttpInvokerUtil.HTTP_METHOD_POST : HttpInvokerUtil.HTTP_METHOD_GET);
                renderConfig.setDynamic(Boolean.parseBoolean(renderConfigObj.getString("isDynamic")));
                renderConfig.getExtraParams().put("removeSelectors", renderConfigObj.getString("removeSelectors"));
                renderConfig.getExtraParams().put("chromeDriverPath", CHROME_DRIVER_PATH);

                PageRule parentPageRule = null;
                if (crawlerPageRulePO.getLevel() != 1) {
                    parentPageRule = pageRules.get(pageRules.size() - 1);
                }
                    // 获取第一级页面规则
                    PageRule pageRule = PageRule.builder()
                            .pageId(crawlerPageRulePO.getId())
                            .pageType(crawlerPageRulePO.getPageType())
                            .crawlerTask(crawlerTask)
                            .level(crawlerPageRulePO.getLevel())
                            .parentRule(parentPageRule)
                            .pageContentType(crawlerPageRulePO.getPageContentType())
                            .ruleName(crawlerPageRulePO.getRuleName())
                            .renderConfig(renderConfig).build();
                    // 查询字段规则
                    List<CrawlerFieldRulePO> crawlerFieldRulePOS = crawlerTaskDao.listCrawlerFieldRules(crawlerPageRulePO.getId());
                    // 组装字段规则
                    List<FieldRule> fieldRules = new ArrayList<>();
                    pageRule.setFieldRules(fieldRules);
                    for (CrawlerFieldRulePO crawlerFieldRulePO:
                            crawlerFieldRulePOS) {
                        FieldRule fieldRule = FieldRule.builder()
                                .fieldId(crawlerFieldRulePO.getId())
                                .rule(crawlerFieldRulePO.getRule())
                                .crawlerTask(crawlerTask)
                                .processConfig(crawlerFieldRulePO.getProcessConfig())
                                .parseType(crawlerFieldRulePO.getParseType())
                                .fieldName(crawlerFieldRulePO.getFieldName())
                                .build();
                        fieldRules.add(fieldRule);
                    }
                    pageRules.add(pageRule);
            }

            // 执行页面抓取
            Map<Integer,List<CapturedPage>> capturedPageLevels = crawlerTaskInst.getCaptureEngine(siteRule, pageRules).execute();
            for(List<CapturedPage> capturedPages:capturedPageLevels.values()){
                System.out.println("---"+capturedPages.size());
            }

            // 抽取最后一层页面字段信息
            PageRule lastPageRule = pageRules.get(pageRules.size()-1);
            if(PageType.CONTENT.getValue() == lastPageRule.getPageType()){
                crawlerTaskInst.getExtractEngine(lastPageRule).executeWithPage(capturedPageLevels.get(lastPageRule.getLevel()));
            }
        } catch (Throwable e) {
            responseResult.setCode(400);
            responseResult.setMsg("触发采集出错");
            log.error("trigger collect occured error", e);
            return responseResult;
        }
        return responseResult;
    }

}
